package com.ae.shield.common.block.tile;

import com.ae.shield.api.IButtonHandler;
import com.ae.shield.common.capability.energy.BlockEnergyStorage;
import com.ae.shield.common.enchantment.EnchantmentWrap;
import com.ae.shield.common.gui.container.ShieldWorkbenchContainer;
import com.ae.shield.common.items.ItemList;
import com.ae.shield.common.items.shieldFittings.makers.ShieldMakerBase;
import com.ae.shield.common.enchantment.shieldSuffix.LevelUp;
import com.ae.shield.common.enchantment.shieldSuffix.SuffixBase;
import com.ae.shield.common.items.shieldFittings.SuffixItem;
import net.minecraft.block.BlockState;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.play.server.SUpdateTileEntityPacket;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.IEnergyStorage;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.templates.FluidTank;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemStackHandler;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;

public class ShieldWorkbenchTile extends TileEntity implements ITickableTileEntity, INamedContainerProvider, IButtonHandler {
    protected ItemStackHandler inventory = new ItemStackHandler(6) {
        @Override
        public boolean isItemValid(int slot, @Nonnull ItemStack stack) {
            if (slot == 0) {
                return stack.getItem() instanceof ShieldMakerBase;
            } else {
                return stack.getItem() instanceof SuffixItem;
            }
        }
    };
    private final LazyOptional<IItemHandler> itemCap = LazyOptional.of(() -> inventory);
    protected FluidTank tank = new FluidTank(10000);
    private final LazyOptional<IFluidHandler> fluidCap = LazyOptional.of(() -> tank);
    protected BlockEnergyStorage energy = new BlockEnergyStorage(10000);
    private final LazyOptional<IEnergyStorage> energyCap = LazyOptional.of(() -> energy);

    public ShieldWorkbenchTile() {
        super(TileEntityList.SHIELD_WORKBENCH_TILE.get());
    }

    @Override
    public void tick() {
        if (!world.isRemote) {
            rebuildShield();
            if (world.getGameTime() % 20 == 0) {
                world.notifyBlockUpdate(pos, getBlockState(), getBlockState(), Constants.BlockFlags.BLOCK_UPDATE);
            }
        }
    }

    private void rebuildShield() {
        ItemStack stackInSlot = inventory.getStackInSlot(0);
        Item item = stackInSlot.getItem();
        if (item instanceof ShieldMakerBase) {
            ((ShieldMakerBase) item).rebuildShield(stackInSlot, energy);
            ((ShieldMakerBase) item).setCD(stackInSlot, 0);
        }
    }

    @Nonnull
    @Override
    public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
        String capName = cap.getName();
        switch (capName.substring(capName.lastIndexOf(".") + 1)) {
            case "IItemHandler":
                return itemCap.cast();
            case "IFluidHandler":
                return fluidCap.cast();
            case "IEnergyStorage":
                return energyCap.cast();
            default:
                return super.getCapability(cap, side);
        }
    }

    @Nullable
    @Override
    public SUpdateTileEntityPacket getUpdatePacket() {
        return new SUpdateTileEntityPacket(pos, 1, getUpdateTag());
    }

    @Override
    public void onDataPacket(NetworkManager net, SUpdateTileEntityPacket pkt) {
        handleUpdateTag(world.getBlockState(pkt.getPos()), pkt.getNbtCompound());
    }

    @Nonnull
    @Override
    public CompoundNBT getUpdateTag() {
        return write(new CompoundNBT());
    }

    @Override
    public void handleUpdateTag(BlockState state, CompoundNBT tag) {
        super.handleUpdateTag(state, tag);
    }

    @Override
    public void read(@Nonnull BlockState state, @Nonnull CompoundNBT compoundNBT) {
        super.read(state, compoundNBT);
        inventory.deserializeNBT(compoundNBT.getCompound("Inventory"));
        tank.readFromNBT(compoundNBT);
        energy.setEnergy(compoundNBT.getInt("Energy"));
    }

    @Nonnull
    @Override
    public CompoundNBT write(@Nonnull CompoundNBT compoundNBT) {
        compoundNBT = super.write(compoundNBT);
        compoundNBT.put("Inventory", inventory.serializeNBT());
        tank.writeToNBT(compoundNBT);
        compoundNBT.putInt("Energy", energy.getEnergyStored());
        return compoundNBT;
    }

    @Nonnull
    @Override
    public ITextComponent getDisplayName() {
        return new TranslationTextComponent("container.aeshield.shield_work_bench");
    }

    @Nullable
    @Override
    public Container createMenu(int id, @Nonnull PlayerInventory playerInv, @Nonnull PlayerEntity player) {
        return new ShieldWorkbenchContainer(id, playerInv, pos);
    }

    public IItemHandler getInventory() {
        return inventory;
    }

    public IEnergyStorage getEnergy() {
        return energy;
    }

    public IFluidHandler getTank() {
        return tank;
    }

    @Override
    public void onButtonPressed(int button) {
        ItemStack makerStack = inventory.getStackInSlot(0);

        if (makerStack.isEmpty() || !(makerStack.getItem() instanceof ShieldMakerBase)) {
            return;
        }

        switch (button) {
            //从护盾中取出
            case 0:
                Map<Enchantment, Integer> enchantments = EnchantmentHelper.getEnchantments(makerStack);
                int enchIndex = 0;
                for (Map.Entry<Enchantment, Integer> ench : enchantments.entrySet()) {
                    if (ench.getKey() instanceof SuffixBase) {
                        if (ench.getKey() instanceof LevelUp) {
                            enchIndex++;
                            continue;
                        }

                        ItemStack suffix = new ItemStack(ItemList.SUFFIX_KID.get());
                        ArrayList<EnchantmentWrap> ens = new ArrayList<>();
                        ens.add(EnchantmentWrap.wrap(ench.getKey(), ench.getValue()));
                        ((SuffixItem) suffix.getItem()).writeSuffix(ens, suffix);
                        boolean done = false;

                        for (int i = 1; i < inventory.getSlots(); i++) {
                            if (inventory.insertItem(i, suffix, true).isEmpty()) {
                                if (energy.extractEnergy(2000, true) != 2000
                                        || tank.drain(250, IFluidHandler.FluidAction.SIMULATE).getAmount() != 250) {
                                    done = true;
                                    break;
                                }
                                tank.drain(250, IFluidHandler.FluidAction.EXECUTE);
                                energy.extractEnergy(2000, false);
                                inventory.insertItem(i, suffix, false);
                                ListNBT list = makerStack.getOrCreateTag().getList("Enchantments", 10);
                                list.remove(enchIndex);

                                done = true;
                                break;
                            } else {
                                if (i == inventory.getSlots() - 1) {
                                    break;
                                }
                            }
                        }

                        if (done) {
                            break;
                        }

                    }
                    enchIndex++;
                }

                ((ShieldMakerBase) makerStack.getItem()).reloadProperty(makerStack);
                break;
            //放入护盾
            case 1:
                for (int i = 1; i < inventory.getSlots(); i++) {
                    ItemStack stack = inventory.getStackInSlot(i);
                    if (!stack.isEmpty() && stack.getItem() instanceof SuffixItem) {
                        ArrayList<EnchantmentWrap> ens = ((SuffixItem) stack.getItem()).readSuffix(stack);

                        if (ens == null || ens.size() == 0) {
                            continue;
                        }

                        boolean done = false;
                        Collection<Enchantment> collection = EnchantmentHelper.getEnchantments(makerStack).keySet();

                        for (EnchantmentWrap en : ens) {
                            if (!EnchantmentHelper.areAllCompatibleWith(collection, en.getEn())) {
                                continue;
                            }

                            if (energy.extractEnergy(2000, true)
                                    == 2000 && tank.drain(250, IFluidHandler.FluidAction.SIMULATE).getAmount() == 250) {
                                energy.extractEnergy(2000, false);
                                tank.drain(250, IFluidHandler.FluidAction.EXECUTE);
                                makerStack.addEnchantment(en.getEn(), en.getLvl());
                                done = true;
                            }
                        }

                        if (done) {
                            inventory.extractItem(i, 1, false);
                        }
                    }
                }
                ((ShieldMakerBase) makerStack.getItem()).reloadProperty(makerStack);
        }
    }
}
